package cn.fyk.sso.client.one.filter;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.util.StringUtils;

import cn.hutool.json.JSONUtil;
import cn.fyk.sso.client.one.pojo.User;

/**
 * @Description:	des
 * @Author:			方宇康
 * @CreateDate:		2020/1/6 11:06
 * @Version:      	1.0.0.1
 * @Company:       联通智网科技有限公司
 */
@Slf4j
public class SsoClientFilter implements Filter
{
	/** 应用一首页 */
	private final String SUCCESS_URL = "/sso/index";

	/** 跳入服务端登录页面 */
	private final String SSO_SERVER_LOGIN_URL = "http://localhost:8080/ssoServer/sso/login";

	/** 服务端用户信息验证 */
	private final String SSO_SERVER_AUTHENTICATION_URL = "http://localhost:8080/ssoServer/sso/authentication";

	private final String SUFFIX_LOGIN = "/login";

	private final String SUFFIX_CSS = "css";

	private final String SUFFIX_JS = "js";

	private final Integer SUCCESS_CODE = 200;

	public static ConcurrentHashMap<String, HttpSession> TICKET_SESSION_CACHE = new ConcurrentHashMap<>();

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
	{
		HttpServletRequest request = (HttpServletRequest )servletRequest;
		HttpServletResponse response = (HttpServletResponse )servletResponse;
		HttpSession session = request.getSession();
		String path = request.getScheme().concat("://").concat(request.getServerName()).concat(":").concat(String.valueOf(request.getServerPort())).concat(request.getContextPath());
		String uri = request.getRequestURI();
		// 被动单点退出
		String requestLogout = request.getParameter("requestLogout");
		if (!StringUtils.isEmpty(requestLogout)) {
			ssoLogout(requestLogout);
			response.sendRedirect(SSO_SERVER_LOGIN_URL.concat("?service=").concat(path));
			return;
		}
		// 根据ticket获取用户信息
		String ticket = request.getParameter("ticket");
		if (!StringUtils.isEmpty(ticket)) {
			User user = this.getUserByTicket(ticket);
			if (user == null) {
				response.sendRedirect(SSO_SERVER_LOGIN_URL.concat("errorMsg=非法访问"));
			} else {
				session.setAttribute("LOGIN_INFO", user);
				response.sendRedirect(path.concat(SUCCESS_URL));
				TICKET_SESSION_CACHE.put(ticket, session);
			}
			return;
		}
		
		User user = (User)session.getAttribute("LOGIN_INFO");
		if (uri.endsWith(this.SUFFIX_LOGIN)) {
			response.sendRedirect(SSO_SERVER_LOGIN_URL.concat("?service=").concat(path));
			return;
		}
		// 用户校验通过、静态资源直接放行
		if (Objects.nonNull(user) || uri.endsWith(this.SUFFIX_CSS) || uri.endsWith(this.SUFFIX_JS))
		{
			filterChain.doFilter(servletRequest, servletResponse);
		}
		else {
			response.sendRedirect(SSO_SERVER_AUTHENTICATION_URL.concat("?service=").concat(path));
		}
		return;
	}

	/**
	 * 退出单点登录
	 *
	 * @param ticket
	 * @return
	 * @exception
	 * @date        2020/1/6 13:46
	 */
	private void ssoLogout(String ticket)
	{
		log.info("SsoClientFilter|ssoLogout|Sso客户端一|退出单点登录|请求入参：={}", ticket);
		if(TICKET_SESSION_CACHE.containsKey(ticket)){
			HttpSession sess = TICKET_SESSION_CACHE.get(ticket);
			if(null != sess){
				sess.invalidate();
			}
			TICKET_SESSION_CACHE.remove(ticket);
		}
	}

	/**
	 * 校验票据
	 *
	 * @param ticket
	 * @return
	 * @exception
	 * @date        2020/1/6 13:47
	 */
	private User getUserByTicket(String ticket)
	{
		User user = null;
		CloseableHttpResponse closeableHttpResponse = null;
		try {
			CloseableHttpClient httpClient = HttpClients.createDefault();
			URI uriHttp = new URI("http://localhost:8080/ssoServer/sso/validateTicket");
			URIBuilder uriBuilder = new URIBuilder(uriHttp);
			uriBuilder.setParameter("ticket", ticket);
			URI uri  = uriBuilder.build();
			HttpGet httpGet = new HttpGet(uri);
			//执行请求访问
			closeableHttpResponse = httpClient.execute(httpGet);
			//获取返回HTTP状态码
			int statusCode = closeableHttpResponse.getStatusLine().getStatusCode();
			if(statusCode == this.SUCCESS_CODE ){
				HttpEntity entity = closeableHttpResponse.getEntity();
				String content = EntityUtils.toString(entity,"UTF-8");
				user = JSONUtil.toBean(content, User.class);
				log.info("SsoClientFilter|getUserByTicket|Sso客户端一|获取用户信息|请求出参：={}", user);
				EntityUtils.consume(entity);
			}
		} catch (ClientProtocolException e) {
			log.error("SsoClientFilter|ClientProtocolException|异常", e);
		} catch (IOException e) {
			log.error("SsoClientFilter|IOException|异常", e);
		} catch (URISyntaxException e) {
			log.error("SsoClientFilter|URISyntaxException|异常", e);
		} finally {
			try {
				closeableHttpResponse.close();
			} catch (IOException e) {
				log.error("SsoClientFilter|finally|IOException|异常", e);
			}
		}
		return user;
	}
}
